xsm: Dynamic update to device ocontexts
authorKeir Fraser <keir.fraser@citrix.com>
Fri, 13 Nov 2009 22:00:19 +0000 (22:00 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Fri, 13 Nov 2009 22:00:19 +0000 (22:00 +0000)
Added the ability to add and delete ocontexts dynamically on a running
system.  Two new commands have been added to the xsm hypercall, add
and delete ocontext.  Twelve new library functions have been
implemented that use the hypercall commands to label and unlabel
pirqs, PCI devices, I/O ports and memory.  The base policy has been
updated so dom0 has the ability to use the hypercall commands by
default.  Items added to the list will not be present next time the
system reloads.  They will need to be added to the static policy.

Signed-off-by : George Coker <gscoker@alpha.ncsc.mil>
Signed-off-by : Paul Nuzzi <pjnuzzi@tycho.ncsc.mil>

tools/flask/libflask/flask_op.c
tools/flask/libflask/include/flask.h
tools/flask/policy/policy/flask/access_vectors
tools/flask/policy/policy/modules/xen/xen.te
xen/include/public/xsm/flask_op.h
xen/xsm/flask/flask_op.c
xen/xsm/flask/include/av_perm_to_string.h
xen/xsm/flask/include/av_permissions.h
xen/xsm/flask/include/security.h
xen/xsm/flask/ss/services.c

index 579be20d96baabb61966b0e314dd44b6bf2b9ac0..9eab033e4dd4e4591db2e4ef58074e6cb0fa61ad 100644 (file)
@@ -109,3 +109,236 @@ int flask_setenforce(int xc_handle, int mode)
 
     return 0;
 }
+
+int flask_add_pirq(int xc_handle, unsigned int pirq, char *scontext)
+{
+    int err;
+    flask_op_t op;
+    char *buf;
+    char *pirq_s = OCON_PIRQ_STR;
+    int size = INITCONTEXTLEN + strlen(pirq_s) + (sizeof(unsigned int)) +
+                (sizeof(char) * 3);
+
+    if ( (buf = (char *) malloc(size)) == NULL )
+        return -ENOMEM;
+    memset(buf, 0, size);
+
+    op.cmd = FLASK_ADD_OCONTEXT;
+    snprintf(buf, size, "%s %255s %u", pirq_s, scontext, pirq);
+    op.buf = buf;
+    op.size = size;
+
+    if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+    {
+        free(buf);
+        return err;
+    }
+
+    free(buf);
+    return 0;
+
+}
+
+int flask_add_ioport(int xc_handle, unsigned long low, unsigned long high,
+                      char *scontext)
+{
+    int err;
+    flask_op_t op;
+    char *buf;
+    char *ioport = OCON_IOPORT_STR;
+    int size = INITCONTEXTLEN + strlen(ioport) +
+                (sizeof(unsigned long) * 2) + (sizeof(char) * 4);
+
+    if ( (buf = (char *) malloc(size)) == NULL )
+        return -ENOMEM;
+    memset(buf, 0, size);
+
+    op.cmd = FLASK_ADD_OCONTEXT;
+    snprintf(buf, size, "%s %255s %li %li", ioport, scontext, low, high);
+    op.buf = buf;
+    op.size = size;
+
+    if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+    {
+        free(buf);
+        return err;
+    }
+
+    free(buf);
+    return 0;
+
+}
+
+int flask_add_iomem(int xc_handle, unsigned long low, unsigned long high,
+                     char *scontext)
+{
+    int err;
+    flask_op_t op;
+    char *buf;
+    char *iomem = OCON_IOMEM_STR;
+    int size = INITCONTEXTLEN + strlen(iomem) +
+                (sizeof(unsigned long) * 2) + (sizeof(char) * 4);
+
+    if ( (buf = (char *) malloc(size)) == NULL )
+        return -ENOMEM;
+    memset(buf, 0, size);
+
+    op.cmd = FLASK_ADD_OCONTEXT;
+    snprintf(buf, size, "%s %255s %li %li", iomem, scontext, low, high);
+    op.buf = buf;
+    op.size = size;
+
+    if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+    {
+        free(buf);
+        return err;
+    }
+
+    free(buf);
+    return 0;
+
+}
+
+int flask_add_device(int xc_handle, unsigned long device, char *scontext)
+{
+    int err;
+    flask_op_t op;
+    char *buf;
+    char *dev = OCON_DEVICE_STR;
+    int size = INITCONTEXTLEN + strlen(dev) + (sizeof(unsigned long)) +
+                (sizeof(char) * 3);
+
+    if ( (buf = (char *) malloc(size)) == NULL )
+        return -ENOMEM;
+    memset(buf, 0, size);
+
+    op.cmd = FLASK_ADD_OCONTEXT;
+    snprintf(buf, size, "%s %255s %li", dev, scontext, device);
+    op.buf = buf;
+    op.size = size;
+
+    if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+    {
+        free(buf);
+        return err;
+    }
+
+    free(buf);
+    return 0;
+
+}
+
+int flask_del_pirq(int xc_handle, unsigned int pirq)
+{
+    int err;
+    flask_op_t op;
+    char *buf;
+    char *pirq_s = OCON_PIRQ_STR;
+    int size = strlen(pirq_s) + (sizeof(unsigned int)) +
+                (sizeof(char) * 2);
+
+    if ( (buf = (char *) malloc(size)) == NULL )
+        return -ENOMEM;
+    memset(buf, 0, size);
+
+    op.cmd = FLASK_DEL_OCONTEXT;
+    snprintf(buf, size, "%s %u", pirq_s, pirq);
+    op.buf = buf;
+    op.size = size;
+
+    if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+    {
+        free(buf);
+        return err;
+    }
+
+    free(buf);
+    return 0;
+
+}
+
+int flask_del_ioport(int xc_handle, unsigned long low, unsigned long high)
+{
+    int err;
+    flask_op_t op;
+    char *buf;
+    char *ioport = OCON_IOPORT_STR;
+    int size = strlen(ioport) + (sizeof(unsigned long) * 2) +
+                (sizeof(char) * 3);
+
+    if ( (buf = (char *) malloc(size)) == NULL )
+        return -ENOMEM;
+    memset(buf, 0, size);
+
+    op.cmd = FLASK_DEL_OCONTEXT;
+    snprintf(buf, size, "%s %li %li", ioport, low, high);
+    op.buf = buf;
+    op.size = size;
+
+    if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+    {
+        free(buf);
+        return err;
+    }
+
+    free(buf);
+    return 0;
+
+}
+
+int flask_del_iomem(int xc_handle, unsigned long low, unsigned long high)
+{
+    int err;
+    flask_op_t op;
+    char *buf;
+    char *iomem = OCON_IOMEM_STR;
+    int size = strlen(iomem) + (sizeof(unsigned long) * 2) +
+                (sizeof(char) * 3);
+
+    if ( (buf = (char *) malloc(size)) == NULL )
+        return -ENOMEM;
+    memset(buf, 0, size);
+
+    op.cmd = FLASK_DEL_OCONTEXT;
+    snprintf(buf, size, "%s %li %li", iomem, low, high);
+    op.buf = buf;
+    op.size = size;
+
+    if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+    {
+        free(buf);
+        return err;
+    }
+
+    free(buf);
+    return 0;
+
+}
+
+int flask_del_device(int xc_handle, unsigned long device)
+{
+    int err;
+    flask_op_t op;
+    char *buf;
+    char *dev = OCON_DEVICE_STR;
+    int size = strlen(dev) + (sizeof(unsigned long)) + (sizeof(char) * 2);
+
+    if ( (buf = (char *) malloc(size)) == NULL )
+        return -ENOMEM;
+    memset(buf, 0, size);
+
+    op.cmd = FLASK_DEL_OCONTEXT;
+    snprintf(buf, size, "%s %li", dev, device);
+    op.buf = buf;
+    op.size = size;
+
+    if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+    {
+        free(buf);
+        return err;
+    }
+
+    free(buf);
+    return 0;
+
+}
index 31f6263404446c0d57d3341c57299c3cdc00a650..44de26bb89b0c3d802cd0fbdc3d21460b3ab1aa6 100644 (file)
@@ -20,5 +20,24 @@ int flask_context_to_sid(int xc_handle, char *buf, uint32_t size, uint32_t *sid)
 int flask_sid_to_context(int xc_handle, int sid, char *buf, uint32_t size);
 int flask_getenforce(int xc_handle);
 int flask_setenforce(int xc_handle, int mode);
+int flask_add_pirq(int xc_handle, unsigned int pirq, char *scontext);
+int flask_add_ioport(int xc_handle, unsigned long low, unsigned long high,
+                      char *scontext);
+int flask_add_iomem(int xc_handle, unsigned long low, unsigned long high,
+                     char *scontext);
+int flask_add_device(int xc_handle, unsigned long device, char *scontext);
+int flask_del_pirq(int xc_handle, unsigned int pirq);
+int flask_del_ioport(int xc_handle, unsigned long low, unsigned long high);
+int flask_del_iomem(int xc_handle, unsigned long low, unsigned long high);
+int flask_del_device(int xc_handle, unsigned long device);
+#define flask_add_single_ioport(x, l, s) flask_add_ioport(x, l, l, s)
+#define flask_add_single_iomem(x, l, s) flask_add_iomem(x, l, l, s)
+#define flask_del_single_ioport(x, l) flask_del_ioport(x, l, l)
+#define flask_del_single_iomem(x, l) flask_del_iomem(x, l, l);
 
+#define OCON_PIRQ_STR   "pirq"
+#define OCON_IOPORT_STR "ioport"
+#define OCON_IOMEM_STR  "iomem"
+#define OCON_DEVICE_STR "pcidevice"
+#define INITCONTEXTLEN  256
 #endif /* __FLASK_H__ */
index 0df71d0a46d2d1b84d7a8330fb935cbbadbf99d8..f835eb5a324b2fae06186a172ee973caf6daf2a7 100644 (file)
@@ -163,4 +163,6 @@ class security
        setenforce
        setbool
        setsecparam
+        add_ocontext
+        del_ocontext
 }
index 851b0d6bd3e0f87eb7bbecb41ffbeece0d319d3b..09779391468a35268f5a7ef5af9c946fd87ab896 100644 (file)
@@ -51,7 +51,7 @@ allow dom0_t xen_t:xen firmware;
 
 allow dom0_t security_t:security {compute_av compute_create compute_member 
 check_context load_policy compute_relabel compute_user setenforce setbool
-setsecparam};
+setsecparam add_ocontext del_ocontext};
 
 create_channel(dom0_t, dom0_t, evchn0-0_t)
 allow dom0_t evchn0-0_t:event {send};
index 7882d73cea9b94499e3d5e127de71e554889533d..2fc1184f104aa26aa58df5499aad459e419d9552 100644 (file)
 #define FLASK_AVC_HASHSTATS     18
 #define FLASK_AVC_CACHESTATS    19
 #define FLASK_MEMBER            20
+#define FLASK_ADD_OCONTEXT      21
+#define FLASK_DEL_OCONTEXT      22
 
-#define FLASK_LAST              FLASK_MEMBER
+#define FLASK_LAST              FLASK_DEL_OCONTEXT
 
 typedef struct flask_op {
     uint32_t  cmd;
index 6d8faaf50c4d32c29a0ea814748b4d512ded8528..f03b01106bad538a77f1bff89bd5a1ae06070ee1 100644 (file)
@@ -45,7 +45,9 @@ integer_param("flask_enabled", flask_enabled);
         1UL<<FLASK_COMMITBOOLS | \
         1UL<<FLASK_DISABLE | \
         1UL<<FLASK_SETAVC_THRESHOLD | \
-        1UL<<FLASK_MEMBER \
+        1UL<<FLASK_MEMBER | \
+        1UL<<FLASK_ADD_OCONTEXT | \
+        1UL<<FLASK_DEL_OCONTEXT \
     )
 
 #define FLASK_COPY_OUT \
@@ -752,6 +754,93 @@ out:
     return length;
 }
 
+static int flask_ocontext_del(char *buf, uint32_t size)
+{
+    int len = 0;
+    char *ocontext;
+    unsigned long low  = 0;
+    unsigned long high = 0;
+
+    len = domain_has_security(current->domain, SECURITY__DEL_OCONTEXT);
+    if ( len )
+        return len;
+
+    if ( (ocontext = xmalloc_bytes(size) ) == NULL )
+        return -ENOMEM;
+
+    len = sscanf(buf, "%s %li %li", ocontext, &low, &high);
+    if ( len < 2 )
+    {
+        len = -EINVAL;
+        goto out;
+    }
+    else if ( len == 2 )
+        high = low;
+
+    if ( low > high )
+    {
+        len = -EINVAL;
+        goto out;
+    }
+
+    len = security_ocontext_del(ocontext, low, high);
+  out:
+    xfree(ocontext);
+    return len;
+}
+
+static int flask_ocontext_add(char *buf, uint32_t size)
+{
+    int len = 0;
+    u32 sid = 0;
+    unsigned long low  = 0;
+    unsigned long high = 0;
+    char *scontext;
+    char *ocontext;
+
+    len = domain_has_security(current->domain, SECURITY__ADD_OCONTEXT);
+    if ( len )
+        return len;
+
+    if ( (scontext = xmalloc_bytes(size) ) == NULL )
+        return -ENOMEM;
+
+    if ( (ocontext = xmalloc_bytes(size) ) == NULL )
+    {
+        xfree(scontext);
+        return -ENOMEM;
+    }
+
+    memset(scontext, 0, size);
+    memset(ocontext, 0, size);
+
+    len = sscanf(buf, "%s %s %li %li", ocontext, scontext, &low, &high);
+    if ( len < 3 )
+    {
+        len = -EINVAL;
+        goto out;
+    }
+    else if ( len == 3 )
+        high = low;
+
+    if ( low > high )
+    {
+        len = -EINVAL;
+        goto out;
+    }
+    len = security_context_to_sid(scontext, strlen(scontext)+1, &sid);
+    if ( len < 0 )
+    {
+        len = -EINVAL;
+        goto out;
+    }
+    len = security_ocontext_add(ocontext, low, high, sid);
+out:
+    xfree(ocontext);
+    xfree(scontext);
+    return len;
+}
+
 long do_flask_op(XEN_GUEST_HANDLE(xsm_op_t) u_flask_op)
 {
     flask_op_t curop, *op = &curop;
@@ -910,6 +999,18 @@ long do_flask_op(XEN_GUEST_HANDLE(xsm_op_t) u_flask_op)
     }
     break;    
 
+    case FLASK_ADD_OCONTEXT:
+    {
+        length = flask_ocontext_add(arg, op->size);
+        break;
+    }
+
+    case FLASK_DEL_OCONTEXT:
+    {
+        length = flask_ocontext_del(arg, op->size);
+        break;
+    }
+
     default:
         length = -ENOSYS;
         break;
index 125aa97a3ee4042b9f0bc5987937b49cbd0ef714..da56d563c979e462729473db5e69b0d010d556f9 100644 (file)
    S_(SECCLASS_SECURITY, SECURITY__SETENFORCE, "setenforce")
    S_(SECCLASS_SECURITY, SECURITY__SETBOOL, "setbool")
    S_(SECCLASS_SECURITY, SECURITY__SETSECPARAM, "setsecparam")
+   S_(SECCLASS_SECURITY, SECURITY__ADD_OCONTEXT, "add_ocontext")
+   S_(SECCLASS_SECURITY, SECURITY__DEL_OCONTEXT, "del_ocontext")
index 23b0117f3eba2ce57fccc2c16e4bcbe9323d44dc..cc1f0a2ccb215592b4842897f5ffdd32f2635e8c 100644 (file)
 #define SECURITY__SETENFORCE                      0x00000080UL
 #define SECURITY__SETBOOL                         0x00000100UL
 #define SECURITY__SETSECPARAM                     0x00000200UL
+#define SECURITY__ADD_OCONTEXT                    0x00000400UL
+#define SECURITY__DEL_OCONTEXT                    0x00000800UL
 
index 149caf753c7fa131ab3d7ae38f8541efd1064c21..8a64b0a3e512b60a2629bbd25aa973b9ec96af9e 100644 (file)
@@ -82,4 +82,8 @@ int security_device_sid(u32 device, u32 *out_sid);
 int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
                                                                     u16 tclass);
 
+int security_ocontext_add(char *ocontext, unsigned long low,
+                           unsigned long high, u32 sid);
+
+int security_ocontext_del(char *ocontext, unsigned int low, unsigned int high);
 #endif /* _FLASK_SECURITY_H_ */
index f841aa710e334ff041f2deba4fcc71ab74c13dc5..6e728009e475f65f5c4c85c63a025ee594940a33 100644 (file)
@@ -1942,3 +1942,277 @@ out:
     xfree(bvalues);
     return rc;
 }
+
+int determine_ocontext( char *ocontext )
+{
+    if ( strcmp(ocontext, "pirq") == 0 )
+        return OCON_PIRQ;
+    else if ( strcmp(ocontext, "ioport") == 0 )
+        return OCON_IOPORT;
+    else if ( strcmp(ocontext, "iomem") == 0 )
+        return OCON_IOMEM;
+    else if ( strcmp(ocontext, "pcidevice") == 0 )
+        return OCON_DEVICE;
+    else
+        return -1;
+}
+
+int security_ocontext_add( char *ocontext, unsigned long low, unsigned long high
+                            ,u32 sid )
+{
+    int ret = 0;
+    int ocon = 0;
+    struct ocontext *c;
+    struct ocontext *add;
+
+    if ( (ocon = determine_ocontext(ocontext)) < 0 )
+        return -EINVAL;
+    if ( (add = xmalloc(struct ocontext)) == NULL )
+        return -ENOMEM;
+    memset(add, 0, sizeof(struct ocontext));
+    add->sid[0] = sid;
+
+    POLICY_WRLOCK;
+    switch( ocon )
+    {
+    case OCON_PIRQ:
+        add->u.pirq = (u16)low;
+        if ( high != low )
+        {
+            ret = -EINVAL;
+            break;
+        }
+
+        c = policydb.ocontexts[OCON_PIRQ];
+        while ( c )
+        {
+            if ( c->u.pirq == add->u.pirq )
+            {
+                printk("%s: Duplicate pirq %d\n", __FUNCTION__, add->u.pirq);
+                ret = -EINVAL;
+                break;
+            }
+            c = c->next;
+        }
+
+        if ( ret == 0 )
+        {
+            add->next = policydb.ocontexts[OCON_PIRQ];
+            policydb.ocontexts[OCON_PIRQ] = add;
+        }
+        break;
+
+    case OCON_IOPORT:
+        add->u.ioport.low_ioport = low;
+        add->u.ioport.high_ioport = high;
+
+        c = policydb.ocontexts[OCON_IOPORT];
+        while ( c )
+        {
+            if ( c->u.ioport.low_ioport <= add->u.ioport.high_ioport &&
+                 add->u.ioport.low_ioport <= c->u.ioport.high_ioport )
+            {
+                printk("%s: IO Port overlap with entry 0x%x - 0x%x\n",
+                       __FUNCTION__, c->u.ioport.low_ioport,
+                       c->u.ioport.high_ioport);
+                ret = -EINVAL;
+                break;
+            }
+            c = c->next;
+        }
+
+        if ( ret == 0 )
+        {
+            add->next = policydb.ocontexts[OCON_IOPORT];
+            policydb.ocontexts[OCON_IOPORT] = add;
+        }
+        break;
+
+    case OCON_IOMEM:
+        add->u.iomem.low_iomem = low;
+        add->u.iomem.high_iomem = high;
+
+        c = policydb.ocontexts[OCON_IOMEM];
+        while ( c )
+        {
+            if ( c->u.iomem.low_iomem <= add->u.iomem.high_iomem &&
+                 add->u.iomem.low_iomem <= c->u.iomem.high_iomem )
+            {
+                printk("%s: IO Memory overlap with entry 0x%x - 0x%x\n",
+                       __FUNCTION__, c->u.iomem.low_iomem,
+                       c->u.iomem.high_iomem);
+                ret = -EINVAL;
+                break;
+            }
+            c = c->next;
+        }
+
+        if ( ret == 0 )
+        {
+            add->next = policydb.ocontexts[OCON_IOMEM];
+            policydb.ocontexts[OCON_IOMEM] = add;
+        }
+        break;
+
+     case OCON_DEVICE:
+        add->u.device = low;
+        if ( high != low )
+        {
+            ret = -EINVAL;
+            break;
+        }
+
+        c = policydb.ocontexts[OCON_DEVICE];
+        while ( c )
+        {
+            if ( c->u.device == add->u.device )
+            {
+                printk("%s: Duplicate PCI Device 0x%x\n", __FUNCTION__,
+                        add->u.device);
+                ret = -EINVAL;
+                break;
+            }
+            c = c->next;
+        }
+
+        if ( ret == 0 )
+        {
+            add->next = policydb.ocontexts[OCON_DEVICE];
+            policydb.ocontexts[OCON_DEVICE] = add;
+        }
+        break;
+
+     default:
+         ret = -EINVAL;
+    }
+    POLICY_WRUNLOCK;
+
+    if ( ret != 0 )
+        xfree(add);
+    return ret;
+}
+
+int security_ocontext_del( char *ocontext, unsigned int low, unsigned int high )
+{
+    int ret = 0;
+    int ocon = 0;
+    struct ocontext *c, *before_c;
+
+    if ( (ocon = determine_ocontext(ocontext)) < 0 )
+        return -EINVAL;
+
+    POLICY_WRLOCK;
+    switch( ocon )
+    {
+    case OCON_PIRQ:
+        for ( before_c = NULL, c = policydb.ocontexts[OCON_PIRQ];
+              c; before_c = c, c = c->next )
+        {
+            if ( c->u.pirq == low )
+            {
+                if ( before_c == NULL )
+                {
+                    policydb.ocontexts[OCON_PIRQ] = c->next;
+                    xfree(c);
+                    goto out;
+                }
+                else
+                {
+                    before_c->next = c->next;
+                    xfree(c);
+                    goto out;
+                }
+            }
+        }
+
+        printk("%s: ocontext not found: pirq %d\n", __FUNCTION__, low);
+        ret = -EINVAL;
+        break;
+
+    case OCON_IOPORT:
+        for ( before_c = NULL, c = policydb.ocontexts[OCON_IOPORT];
+              c; before_c = c, c = c->next )
+        {
+            if ( c->u.ioport.low_ioport == low &&
+                 c->u.ioport.high_ioport == high )
+            {
+                if ( before_c == NULL )
+                {
+                    policydb.ocontexts[OCON_IOPORT] = c->next;
+                    xfree(c);
+                    goto out;
+                }
+                else
+                {
+                    before_c->next = c->next;
+                    xfree(c);
+                    goto out;
+                }
+            }
+        }
+
+        printk("%s: ocontext not found: ioport 0x%x - 0x%x\n", __FUNCTION__,
+                low, high);
+        ret = -EINVAL;
+        break;
+
+    case OCON_IOMEM:
+        for ( before_c = NULL, c = policydb.ocontexts[OCON_IOMEM];
+              c; before_c = c, c = c->next )
+        {
+            if ( c->u.iomem.low_iomem == low &&
+                 c->u.iomem.high_iomem == high )
+            {
+                if ( before_c == NULL )
+                {
+                    policydb.ocontexts[OCON_IOMEM] = c->next;
+                    xfree(c);
+                    goto out;
+                }
+                else
+                {
+                    before_c->next = c->next;
+                    xfree(c);
+                    goto out;
+                }
+            }
+        }
+
+        printk("%s: ocontext not found: iomem 0x%x - 0x%x\n", __FUNCTION__,
+                low, high);
+        ret = -EINVAL;
+        break;
+
+    case OCON_DEVICE:
+        for ( before_c = NULL, c = policydb.ocontexts[OCON_DEVICE];
+              c; before_c = c, c = c->next )
+        {
+            if ( c->u.device == low )
+            {
+                if ( before_c == NULL )
+                {
+                    policydb.ocontexts[OCON_DEVICE] = c->next;
+                    xfree(c);
+                    goto out;
+                }
+                else
+                {
+                    before_c->next = c->next;
+                    xfree(c);
+                    goto out;
+                }
+            }
+        }
+
+        printk("%s: ocontext not found: pcidevice 0x%x\n", __FUNCTION__, low);
+        ret = -EINVAL;
+        break;
+
+    default:
+        ret = -EINVAL;
+    }
+
+  out:
+    POLICY_WRUNLOCK;
+    return ret;
+}